package Principal;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.lcdui.StringItem;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;


/**
 * Clase moneda. Almacena, para cada tipo de moneda, su código y la equivalencia con la moneda
 * de referencia.
 * @author Noelia Alonso Garrido
 * @author Abel Torres Alonso
 * @author Diego Vallejo Alonso
 */
public class Moneda {

    private static String referencia = "EUR";   //Código de la moneda de referencia
    private String codigo;                      //Código de la moneda
    private float equivalencia;                 //Equivalencia con la moneda de referencia
    private String nombre;                      //Nombre de la moneda

    /**
     * Constructor sin argumentos. Deja en null el código y a 0 la equivalencia
     */
    public Moneda() {
        this.codigo = null;
        this.equivalencia = 0;
        this.nombre = null;
    }

    /**
     * Constructor con argumentos.
     * @param c El código de la moneda. Debe existir y ser válido.
     * @param e Su equivalencia
     */
    public Moneda(String n, String c, float e) {
        this.nombre = n;
        this.codigo = c.toUpperCase();
        this.equivalencia = e;
    }

    /**
     * Establece la nueva moneda de referencia.
     * @param r El código de la nueva moneda de referencia. Debe existir y ser válido.
     */
    public static void setReferencia(String r) {
        referencia = r;
    }

    /**
     * Devuelve la moneda de referencia actual
     * @return El código de la moneda de referencia actual
     */
    public static String getReferencia() {
        return referencia;
    }

    /**
     * Devuelve la equivalencia de esta moneda respecto a la moneda de referencia
     * @return la equivalencia de esta moneda.
     */
    public float getEquivalencia() {
        return this.equivalencia;
    }

    /**
     * Transforma una cantidad de esta moneda a la cantidad en la moneda de referencia
     * @param c La cantidad a transformar
     * @return La cantidad transformada a la moneda de equivalencia
     */
    public float cantidadEquivalente(float c) {
        if (this.codigo.equals(referencia)) {       //Si nuestra moneda ya es la de equivalencia, no es necesario convertir
            return c;
        } else {
            return (c * this.equivalencia);
        }
    }

    /**
     * Devuelve el código de la moneda
     * @return el código de la moneda.
     */
    public String getCodigo() {
        return this.codigo;
    }

    /**
     * Convierte el objeto a un vector de bytes listo para ser almacenado en un Registro
     * @return el objeto al que se llama con este método serializado
     * @throws IOException
     */
    public byte[] aByteArray() throws IOException {

        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        DataOutputStream dout = new DataOutputStream(bout);

        dout.writeUTF(referencia);
        dout.writeUTF(this.nombre);
        dout.writeUTF(this.codigo);
        dout.writeFloat(this.equivalencia);
        dout.flush();
        return bout.toByteArray();

    }

    /**
     * Establece los valores del objeto a los obtenidos a partir de un array de bytes
     * extraído de un Registro.
     * @param data Array de Bytes con los datos de una moneda serializada.
     * @throws IOException
     */
    public void desdeByteArray(byte[] data) throws IOException {

        ByteArrayInputStream bin = new ByteArrayInputStream(data);
        DataInputStream din = new DataInputStream(bin);

        referencia = din.readUTF();
        this.nombre = din.readUTF();
        this.codigo = din.readUTF();
        this.equivalencia = din.readFloat();
    }

    public String toString() {
        String linea;

        if (this.codigo.equals(referencia)) {
            linea = (this.nombre + " " + "(Moneda de referencia)");
        } else {
            linea = (this.nombre + " , equivalencia: " + this.codigo + "/" + referencia + ":" + this.equivalencia);
        }

        return linea;
    }

    /**
    * Indica si una moneda es la referencia.
    * @return
    */
    public boolean esReferencia() {
        if (this.codigo.equals(referencia)) {
            return true;
        } else {
            return false;
        }
    }


    /**
     * Actualiza la equivalencia de esta moneda con respecto a la moneda de referencia.
     * Realiza una peticion GET al servidor de la URL seleccionada y espera la respuesta.
     * Despues de procesar la respuesta y extraer el valor con respecto a la referencia cierra
     * la conexión
     */
    public void actualizaEquivalencia() throws IOException {
        String mensajeError=null;
        HttpConnection http = null;
        InputStream is = null;
        boolean result = false;

        // Con GET los datos se pasan al final de la url
        String url = "http://download.finance.yahoo.com/d/quotes?s="+this.codigo+this.referencia+"=X&f=sl1";

            http = (HttpConnection) Connector.open(url);

            // Petición desde el cliente
            //-----------------------------
            // Se fijan los datos de la petición
            // método: GET
            http.setRequestMethod(HttpConnection.GET);
            // información de cabecera: opcional para GET
            http.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
            http.setRequestProperty("Content-Language", "es-ES");
            // Enviar datos (con get, ya están al final de la URL)
            // Respuesta desde el servidor
            //-----------------------------
            is = http.openInputStream();
            result = procesarRespuesta(http, is);
            //Cerramos el InputStream y la conexión
            is.close();
            http.close();
    }

     /**
     * A partir de la conexión y el InputStream abierto procesa la respuesta.
     * Si se conoce la longitud de los datos se introducen en un array de bytes.
     * Si se desconoce la longitud de los datos se introducen en un ByteArrayOutputStream.
     * Con cualquiera de las dos maneras se elabora una cadena de la que se extrae el valor de la
     * equivalencia.
     * @param http Conexion abierta con el servidor de la URL
     * @param is InputStream abierto al que llega la respuesta
     * @return Si la conexión se ha realizado correctamente
     * @throws IOException
     */
    public boolean procesarRespuesta(HttpConnection http, InputStream is) throws IOException {
        StringItem respuesta=null;
        String mensajeError = null;
        int i=0;
        String str2;
        Float valor=null;
        Float cambio;

        // 1) Obtener estado
        if (http.getResponseCode() == HttpConnection.HTTP_OK) {
        // 2) Obtener datos
            int length = (int) http.getLength();
            String str;
            if (length != -1) {
                byte datos[] = new byte[length];
                is.read(datos);
                str = new String(datos);
            } else { // longitud no disponible
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                int b;
                while ((b = is.read()) != -1) {
                    baos.write(b);
                }
                str = new String(baos.toByteArray());
                baos.close();
             }
        // 3) Transformar Datos
        str2 = new String();
        //Primera Ocurrencia de la coma
        i=str.indexOf(',', 0);
        //Extraemos la cadena que va desde la coma al final
        str2=str.substring(i+1);
        //Asignamos el valor en float a partir de la subcadena
        cambio=valor.valueOf(str2);
        setEquivalencia(cambio);
        } else {
            mensajeError = http.getResponseCode() + ": " + http.getResponseMessage();
        }

        return (http.getResponseCode() == HttpConnection.HTTP_OK);
    }

    /**
    * Asigna la equivalencia de una moneda con respecto a la de referencia.
    * @param cantidad Cantidad extraida de la respuesta del servidor.
    */
    public void setEquivalencia(Float cantidad){
        float aux;

        aux=cantidad.floatValue();
        this.equivalencia=aux;
    }

}